﻿#include <cstdio>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h> 

extern "C" {
#include <libavutil/opt.h>
#include <libavutil/samplefmt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>

#include <libavformat/avio.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
#include <libavutil/bprint.h>
}

#define INPUT_SAMPLERATE 32000
#define INPUT_FORMAT AV_SAMPLE_FMT_S16
#define INPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_MONO

typedef struct WAVE_HEADER {
    char       id[4];               // four character code, "RIFF"
    uint32_t   fileLength;          // file total length, don't care it
    char       waveFlag[4];    // four character code, "WAVE"
} WaveHeader;

typedef struct WAVE_FORMAT
{
    char     id[4];              // four character code, "fmt "
    uint32_t blockSize;          // Length of the fmt data (=16)
    uint16_t formatTag;          // WAVE File Encoding Tag
    uint16_t channels;           // Channels: 1 = mono, 2 = stereo
    uint32_t samplesPerSec;      // Samples per second: e.g., 44100
    uint32_t avgBytesPerSec;     // sample rate * block align
    uint16_t blockAlign;         // channels * bits/sample / 8
    uint16_t  bitsPerSample;     // 8 or 16
}WaveFormat;

typedef struct  WAVE_DATA
{
    char     id[4];            // four character code "data"
    uint32_t dataLength;       // Sample data size(n)
} WaveData;



/**
 * Convert PCM16LE raw data to WAVE format
 * @param pcmpath       Input PCM file.
 * @param channels      Channel number of PCM file.
 * @param sampleRate   Sample rate of PCM file.
 * @param wavepath      Output WAVE file.
 */
int pcmToWave(const char* pcmpath, int channels, int sampleRate, const char* wavepath)
{

    if (channels == 2 || sampleRate == 0)
    {
        channels = 2;
        sampleRate = 44100;
    }
    int bits = 16;

    WaveHeader    pcmHeader;
    WaveFormat    pcmFmt;
    WaveData      pcmData;

    FILE* fp, * fpout;

    fp = fopen(pcmpath, "rb+");
    if (fp == NULL)
    {
        fprintf(stderr, "open pcm file error.\n");
        return -1;
    }

    fpout = fopen(wavepath, "wb+");
    if (fpout == NULL)
    {
        fprintf(stderr, "create wav file error.\n");
        fclose(fp);
        return -1;
    }

    /* WAVE_HEADER */
    memcpy(pcmHeader.id, "RIFF", strlen("RIFF"));
    memcpy(pcmHeader.waveFlag, "WAVE", strlen("WAVE"));
    //移动指针位置，否则写入二进制流时，会覆盖之前写入的数据。
    fseek(fpout, sizeof(WAVE_HEADER), 1);   //1=SEEK_CUR


    /* WAVE_FORMAT */
    memcpy(pcmFmt.id, "fmt ", strlen("fmt "));
    pcmFmt.blockSize = 16;
    pcmFmt.formatTag = 1;
    pcmFmt.channels = channels;//2此处声道需要要根据实际的文件填写
    pcmFmt.samplesPerSec = sampleRate;
    pcmFmt.bitsPerSample = bits;

    /* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */
    pcmFmt.avgBytesPerSec = pcmFmt.samplesPerSec * pcmFmt.channels * pcmFmt.bitsPerSample / 8;//**

   /* ==wChannels*uiBitsPerSample/8 */
    pcmFmt.blockAlign = pcmFmt.channels * pcmFmt.bitsPerSample / 8;//**

    //1.写入FMT结构数据
    fwrite(&pcmFmt, sizeof(WAVE_FORMAT), 1, fpout);

    /* WAVE_DATA */
    memcpy(pcmData.id, "data", strlen("data"));
    pcmData.dataLength = 0;
    fseek(fpout, sizeof(WAVE_DATA), SEEK_CUR);

    //2.写入数据文件（先读文件，再判断是否eof，是eof那之前读取的数据就无效了）
    unsigned short mPcmData = 0;
    fread(&mPcmData, sizeof(unsigned short), 1, fp);
    while (!feof(fp))
    {
        pcmData.dataLength += 2;
        fwrite(&mPcmData, sizeof(unsigned short), 1, fpout);
        fread(&mPcmData, sizeof(unsigned short), 1, fp);
    }

    pcmHeader.fileLength = 36 + pcmData.dataLength;

    //3.写入Head头结构
    rewind(fpout);
    fwrite(&pcmHeader, sizeof(WAVE_HEADER), 1, fpout);
    fseek(fpout, sizeof(WAVE_FORMAT), SEEK_CUR);
    fwrite(&pcmData, sizeof(WAVE_DATA), 1, fpout);

    fclose(fp);
    fclose(fpout);

    return 0;
}

int main()
{
    int ret = -1;

    const char* pPcmFilename = "input.raw";
    const char* pWavFilename = "output.wav";

    ret = pcmToWave(pPcmFilename, 1, 32000, pWavFilename);

    if (0 != ret)
    {
        return -1;
    }

    // 初始化FFmpeg
    av_register_all();
    avcodec_register_all();
    avformat_network_init();

    AVFormatContext* pAvFmtCtx = nullptr;
    AVCodecContext* pCodecCtx = nullptr;

    AVFilterContext* pAbuffersrcCtx = nullptr;
    AVFilterContext* pVolumeFilterCtx = nullptr;
    AVFilterContext* pAformatFilterCtx = nullptr;
    AVFilterContext* pLowpassFilterCtx = nullptr;
    AVFilterContext* pHighpassFilterCtx = nullptr;
    AVFilterContext* pAbuffersinkCtx = nullptr;

    AVFilterGraph* pFilterGraph = nullptr;


    do
    {
        pAvFmtCtx = avformat_alloc_context();
        if (pAvFmtCtx == NULL)
        {
            fprintf(stderr, "Error opening formatCtx\n");
            ret = -1;
            break;
        }

        if (avformat_open_input(&pAvFmtCtx, pWavFilename, nullptr, nullptr) != 0)
        {
            fprintf(stderr, "Error opening input file\n");
            ret = -1;
            break;
        }

        if (avformat_find_stream_info(pAvFmtCtx, nullptr) < 0)
        {
            fprintf(stderr, "Could not find stream information\n");
            ret = -1;
            break;
        }

        AVCodec* codec = avcodec_find_decoder(pAvFmtCtx->streams[0]->codecpar->codec_id);
        if (codec == NULL)
        {
            fprintf(stderr, "Could not find AVCodec\n");
            ret = -1;
            break;
        }

        pCodecCtx = avcodec_alloc_context3(codec);
        if (pCodecCtx == NULL)
        {
            fprintf(stderr, "Could not find AVCodecContext\n");
            ret = -1;
            break;
        }

        avcodec_parameters_to_context(pCodecCtx, pAvFmtCtx->streams[0]->codecpar);
        avcodec_open2(pCodecCtx, codec, nullptr);


        // 创建音频过滤器图
        AVFilterGraph* pFilterGraph = avfilter_graph_alloc();
        if (pFilterGraph == NULL)
        {
            fprintf(stderr, "alloc filter graph failed.");
            ret = -1;
            break;
        }

        //声音过滤器进口
        {
            const AVFilter* pAbufferFilter = avfilter_get_by_name("abuffer");
            if (pAbufferFilter == NULL)
            {
                fprintf(stderr, "Could not find AVFilter abuffer.");
                ret = -1;
                break;
            }

            //声音进口过滤器参数
            AVBPrint args;
            av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
            av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
                1, pCodecCtx->sample_rate,
                pCodecCtx->sample_rate,
                av_get_sample_fmt_name(pCodecCtx->sample_fmt));

            char ch_layout[64] = { 0 };
            av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, INPUT_CHANNEL_LAYOUT);
            av_bprintf(&args, ":channel_layout=%s",
                ch_layout);


            avfilter_graph_create_filter(&pAbuffersrcCtx, pAbufferFilter, "in", args.str, nullptr, pFilterGraph);

            av_opt_set_bin(pAbuffersrcCtx, "sample_fmts", (uint8_t*)&pCodecCtx->sample_fmt, sizeof(pCodecCtx->sample_fmt), AV_OPT_SEARCH_CHILDREN);
            av_opt_set_bin(pAbuffersrcCtx, "channel_layouts", (uint8_t*)&pCodecCtx->channel_layout, sizeof(pCodecCtx->channel_layout), AV_OPT_SEARCH_CHILDREN);
            av_opt_set_bin(pAbuffersrcCtx, "sample_rates", (uint8_t*)&pCodecCtx->sample_rate, sizeof(pCodecCtx->sample_rate), AV_OPT_SEARCH_CHILDREN);

        }


        //增加声音增益 
        {
            const AVFilter* pVolumeFilter = avfilter_get_by_name("volume");
            if (pVolumeFilter == NULL)
            {
                fprintf(stderr, "Could not find AVFilter volume.");
                ret = -1;
                break;
            }

            avfilter_graph_create_filter(&pVolumeFilterCtx,
                pVolumeFilter,
                "volume", "volume=2.0", nullptr, pFilterGraph);

        }

        {

            const AVFilter* pAformatFilter = avfilter_get_by_name("aformat");
            if (!pAformatFilter)
            {
                fprintf(stderr, "Could not find the aformat filter.\n");
                return AVERROR_FILTER_NOT_FOUND;
            }

            //声音进口过滤器参数
            AVBPrint args;
            av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
            av_bprintf(&args, "sample_fmts=%s:sample_rates=%d",
                av_get_sample_fmt_name(INPUT_FORMAT), INPUT_SAMPLERATE,
                (uint64_t)INPUT_CHANNEL_LAYOUT);

            char ch_layout[64] = { 0 };
            av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, INPUT_CHANNEL_LAYOUT);
            av_bprintf(&args, ":channel_layouts=%s",
                ch_layout);

            avfilter_graph_create_filter(&pAformatFilterCtx, pAformatFilter, "in", args.str, nullptr, pFilterGraph);


        }


        //创建过滤高
        {
            const AVFilter* pLowpassFilter = avfilter_get_by_name("lowpass");
            if (pLowpassFilter == NULL)
            {
                fprintf(stderr, "Could not find AVFilter lowpass.");
                ret = -1;
                break;
            }

            avfilter_graph_create_filter(&pLowpassFilterCtx,
                pLowpassFilter, "lowpass", "2000", nullptr, pFilterGraph);
        }

        //声音过滤
        {
            const AVFilter* pHighpassFilter = avfilter_get_by_name("highpass");
            if (pHighpassFilter == NULL)
            {
                fprintf(stderr, "Could not find AVFilter highpass.");
                ret = -1;
                break;
            }

            avfilter_graph_create_filter(&pHighpassFilterCtx,
                pHighpassFilter,
                "highpass", "200", nullptr, pFilterGraph);
        }



        {

            const AVFilter* pAbuffersinkFilter = avfilter_get_by_name("abuffersink");
            if (pAbuffersinkFilter == NULL)
            {
                fprintf(stderr, "Could not find AVFilter abuffersink.");
                ret = -1;
                break;
            }

            avfilter_graph_create_filter(&pAbuffersinkCtx, pAbuffersinkFilter, "out", nullptr, nullptr, pFilterGraph);
        }


        // 连接过滤器
        avfilter_link(pAbuffersrcCtx, 0, pVolumeFilterCtx, 0);
        avfilter_link(pVolumeFilterCtx, 0, pAformatFilterCtx, 0);
        avfilter_link(pAformatFilterCtx, 0, pLowpassFilterCtx, 0);
        avfilter_link(pLowpassFilterCtx, 0, pHighpassFilterCtx, 0);
        avfilter_link(pHighpassFilterCtx, 0, pAbuffersinkCtx, 0);

        //avfilter_link(pVolumeFilterCtx, 0, pLowpassFilterCtx, 0);
        //avfilter_link(pLowpassFilterCtx, 0, pHighpassFilterCtx, 0);
        //avfilter_link(pHighpassFilterCtx, 0, pAbuffersinkCtx, 0);

        //为滤镜图中的所有滤镜建立连接
        avfilter_graph_config(pFilterGraph, nullptr);

        AVPacket packet;
        av_init_packet(&packet);

        FILE* fpout;
        fpout = fopen("out2.pcm", "wb+");
        if (fpout == NULL)
        {
            fprintf(stderr, "open pcm file error.\n");
            return -1;
        }

        while (av_read_frame(pAvFmtCtx, &packet) >= 0)
        {
            if (packet.stream_index == 0)
            {
                if (avcodec_send_packet(pCodecCtx, &packet) == 0)
                {
                    int numBytes = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
                    AVFrame* outAvFrame = av_frame_alloc();
                    while (avcodec_receive_frame(pCodecCtx, outAvFrame) == 0)
                    {
                        // 发送音频帧到过滤器图
                        av_buffersrc_add_frame_flags(pAbuffersrcCtx, outAvFrame, AV_BUFFERSRC_FLAG_KEEP_REF);

                        AVFrame* filteredFrame = av_frame_alloc();
                        if (av_buffersink_get_frame(pAbuffersinkCtx, filteredFrame) >= 0)
                        {
                            fwrite(filteredFrame->data[0], 1, filteredFrame->linesize[0], fpout);
                            int nbSample = filteredFrame->nb_samples;
                            int channels = filteredFrame->channels;

                            std::cout << "filteredFrame->nb_samples:" << nbSample << std::endl;
                            std::cout << "filteredFrame->channels:" << channels << std::endl;
                            std::cout << "filteredFrame->numBytes:" << numBytes << std::endl;

                            int nbWindowSize = ceil(nbSample / 512.0); //计算当前的窗口数,向上取整

                            for (int n = 0; n < nbWindowSize; n++) //加窗函数,距形窗口
                            {
                                int nbStartSample = n * 512; //计算窗函数开始采样点
                                int nbEndSample = nbStartSample + 512 > nbSample ? nbSample : nbStartSample + 512; //计算窗函数结束位置采样点

                                std::cout << "nbStartSample:" << nbStartSample;
                                std::cout << ",nbEndSample:" << nbEndSample << std::endl;

                            }
                            // 处理过滤后的音频帧
                            // 在这里您可以对过滤后的音频帧进行处理或保存
                        }
                        av_frame_free(&filteredFrame);
                    }
                    av_frame_free(&outAvFrame);
                }
            }
            av_packet_unref(&packet);
        }

        fclose(fpout);

        ret = 0;
    } while (0);

    //清理过滤器
    if (pAbuffersrcCtx) { avfilter_free(pAbuffersrcCtx); }
    if (pVolumeFilterCtx) { avfilter_free(pVolumeFilterCtx); }
    if (pLowpassFilterCtx) { avfilter_free(pLowpassFilterCtx); }
    if (pHighpassFilterCtx) { avfilter_free(pHighpassFilterCtx); }
    if (pAbuffersinkCtx) { avfilter_free(pAbuffersinkCtx); }

    //清理过滤器
    if (pFilterGraph) { avfilter_graph_free(&pFilterGraph); }


    if (pAvFmtCtx) { avformat_close_input(&pAvFmtCtx); }
    if (pCodecCtx) { avcodec_free_context(&pCodecCtx); }

    avformat_network_deinit();
    avcodec_register_all();

    return ret;
}